package top.codetheory.thread._006_JMM;

import lombok.extern.slf4j.Slf4j;

/**
 * @author:
 * @since: 2024/5/8 下午5:59
 **/
@Slf4j
public class _001_打断_and_犹豫模式 {
    /**
     * <p>使用单例前</p>
     * <img src="https://gitee.com/codetheory/img-on1/raw/master/img01/1715163410670-2024-5-818:16:50.png"  />
     * <p>使用单例后</p>
     *<img src="https://gitee.com/codetheory/img-on1/raw/master/img01/1715163335565-2024-5-818:15:35.png"  />
     * <p>可以看到, 使用单例前, 调用了3次start, 那么就会启动三个线程, 在同一时间打印日志, 但是使用了单例后, 就只有一个线程了</p>
     *
     */
    public static void main(String[] args) {
//        TPTVolatile tptVolatile = new TPTVolatile();
//        tptVolatile.start();
//        tptVolatile.start();
//        tptVolatile.start();
        test1();
    }

    /**
     * <p>发现启动的线程, 就算没有变量指向他, 他也不会销毁, 会一直执行</p>
     * <img src="https://gitee.com/codetheory/img-on1/raw/master/img01/1715163757151-2024-5-818:22:37.png"  />
     * <p>chat gpt的解释</p>
     *<img src="https://gitee.com/codetheory/img-on1/raw/master/img01/1715163931268-2024-5-818:25:31.png"  />
     */
    public static void test1() {
        Thread t1 = new Thread(()->{
            while (true) {
                try {
                    Thread.sleep(1000);
                    log.info("info");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"t1");
        t1.start();
        t1 = new Thread(()->{
            while (true) {
                try {
                    Thread.sleep(1000);
                    log.info("info");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"t2");
        t1.start();
        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
@Slf4j
class TPTVolatile {
    private Thread thread;
    private volatile boolean stop = false;  // 因为这里只有一个线程，所以stop只用保证可见性就可以
    private boolean started = false;  // 可以不用加 volatile 因为使用了synchronized, 他可以保证可见性，
    // 而且使用volatile会有问题，volatile只是保证了可见性，当一个线程判断started是false，还没来得及修改的时候，另外一个线程也来判断started，此时也为false

    // 只需要创建一个线程, 相当于单例
    public void start() {
        // 犹豫模式实现
        // 如果不加锁, 想象多个线程进来, 判断started为false, 那么就还是会创建多个线程
        synchronized (this) {
            if (started) {
                // 如果已经启动了, 那就直接返回
                return;
            }
            started = true;
        }

        thread = new Thread(() -> {
            while (true) {
                if (stop) {
                    log.info("料理后事");
                    break;
                }
                try {
                    Thread.sleep(1000);  // 防止cpu空转
                    log.info("执行业务");
                } catch (InterruptedException e) {
                    log.info("被打断了");
                }

            }
        }, "t1");
        thread.start();
    }

    public void stop() {
        stop = true;
        thread.interrupt();  // 让线程能立即停止
    }
}